{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Parte 8 bis - Introducción a Protocolos\n",
    "\n",
    "### Contexto \n",
    "\n",
    "Ahora que hemos visto planes, introduciremos un nuevo objeto llamado el protocolo. Un protocolo coordina una secuencia de planes, los lanza en trabajadores distantes y los corre en una sola pasada.\n",
    "\n",
    "Es un objeto de alto nivel el cual contiene la lógica de una computación compleja distribuida por varios trabajadores. La característica más importante de un protocolo es la habilidad de ser enviado/ buscado / extraído de vuelta entre trabajadores, y finalmente lanzado a trabajadores identificados. Entonces un usuario puede diseñar un protocolo, subirlo a un trabajador en la nube y otros trabajadores podrán buscarlo, descargarlo y aplicar el programa que está contenido en los trabajadores que están conectados.\n",
    "\n",
    "¡Veamos como podemos usarlo!\n",
    "\n",
    "Autores:\n",
    "- Théo Ryffel - Twitter [@theoryffel](https://twitter.com/theoryffel) - GitHub: [@LaRiffle](https://github.com/LaRiffle)\n",
    "\n",
    "Traductores:\n",
    "- Arturo Márquez Flores - Twitter: [@arturomf94](https://twitter.com/arturomf94) \n",
    "- Ricardo Pretelt - Twitter: [@ricardopretelt](https://twitter.com/ricardopretelt)\n",
    "- Carlos Salgado - Github: [@socd06](https://github.com/socd06)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. Crear y lanzar"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Los protocolos son creados al proveer un lista de parejas `(trabajador, plan)`. `trabajador` puede ser un trabajador real o un id de trabajador o una cadena de caracteres que representan un trabajador ficticio. Este último caso puede ser usado en la creación para especificar que 2 planes deben ser apropiados (o no) por el mismo trabajador en el lanzamiento. `plan` puede ser un plan o un _PointerPlan_  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch as th\n",
    "import syft as sy\n",
    "hook = sy.TorchHook(th)\n",
    "\n",
    "# IMPORTANTE: El trabajador local no debe ser un trabajador cliente\n",
    "hook.local_worker.is_client_worker = False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Vamos a definir 3 planes y alimentarlos a un protocolo. Todos ellos realizan una operación de incremento."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@sy.func2plan(args_shape=[(1,)])\n",
    "def inc1(x):\n",
    "    return x + 1\n",
    "\n",
    "@sy.func2plan(args_shape=[(1,)])\n",
    "def inc2(x):\n",
    "    return x + 1\n",
    "\n",
    "@sy.func2plan(args_shape=[(1,)])\n",
    "def inc3(x):\n",
    "    return x + 1\n",
    "\n",
    "protocol = sy.Protocol([(\"worker1\", inc1), (\"worker2\", inc2), (\"worker3\", inc3)])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahora necesitamos conectar el protocolo a los trabajadores, lo cual es realizado llamando `.deploy(*workers)`. Vamos a crear algunos trabajadores."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob = sy.VirtualWorker(hook, id=\"bob\")\n",
    "alice = sy.VirtualWorker(hook, id=\"alice\")\n",
    "charlie = sy.VirtualWorker(hook, id=\"charlie\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "workers = alice, bob, charlie\n",
    "\n",
    "protocol.deploy(*workers)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tú puedes ver que los planes han sido enviados a los trabajadores apropiados: se ha lanzado!\n",
    "\n",
    "Esto se ha hecho en 2 fases: primero, mapeamos los trabajadores ficticios obtenidos en la creación (llamados por cadenas) a los trabajadores obtenidos, y segundo, enviamos los planes correspondientes a cada uno."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. Correr un protocolo\n",
    "\n",
    "Correr un protocolo significa ejecutar todos los planes secuencialmente. Para hacer esto, provees algunas entradas que son enviadas a ubicación del primer plan. El primer plan es ejecutado y su resultado es movido a la ubicación del segundo plan, y así. El resultado final es obtenido después de que se han ejecutado todos los planes, y está compuesto de punteros hasta la última ubicación de plan."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = th.tensor([1.0])\n",
    "ptr = protocol.run(x)\n",
    "ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ptr.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La entrada 1.0 ha pasado por 3 planes y ha incrementado 3 veces, por eso ahora es igual a 4!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "En realidad, tu puedes **correr un protocolo remotamente** en algunos punteros a los datos:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "james = sy.VirtualWorker(hook, id=\"james\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "protocol.send(james)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = th.tensor([1.0]).send(james)\n",
    "ptr = protocol.run(x)\n",
    "ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Como ves el resultado es un puntero a james"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ptr = ptr.get()\n",
    "ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ptr = ptr.get()\n",
    "ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Buscar por un protocolo\n",
    "\n",
    "En una configuración real tú podrías querer descargar un protocolo remoto, para lanzarlo en tus trabajadores y ejecutarlo con tus datos:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Vamos a iniciar un protocolo **el cual no está lanzado**, y ponerlo en un trabajador remoto"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "protocol = sy.Protocol([(\"worker1\", inc1), (\"worker2\", inc2), (\"worker3\", inc3)])\n",
    "protocol.tag('my_protocol')\n",
    "protocol.send(james)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "me = sy.hook.local_worker # consigue acceso a me como un trabajador local"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahora lanzamos una búsqueda para encontrar el protocolo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "responses = me.request_search(['my_protocol'], location=james)\n",
    "responses"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tú tienes acceso a un puntero al protocolo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ptr_protocol = responses[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "como un puntero cualquiera, tú puedes traerlo de vuelta:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "protocol_back = ptr_protocol.get()\n",
    "protocol_back"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "y podemos hacer lo que hicimos en partes 1. & 2."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "protocol_back.deploy(alice, bob, charlie)\n",
    "\n",
    "x = th.tensor([1.0])\n",
    "ptr = protocol_back.run(x)\n",
    "ptr.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Más ejemplos del mundo real vendrán con protocolos, pero enseguida puedes ver todas las posibilidades que se abren por este nuevo objeto!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Dale una Estrella a PySyft en Github\n",
    "\n",
    "La forma más fácil de ayudar a nuestra comunidad es guardando con una estrella los Repos! Esto ayuda a crear consciencia de las geniales herramientas que estamos construyendo.\n",
    "\n",
    "- [Dale una estrella a PySyft](https://github.com/OpenMined/PySyft)\n",
    "\n",
    "### ¡Usa nuestros tutoriales en Github!\n",
    "\n",
    "Hicimos muy buenos tutoriales para conseguir un mejor entendimiento de lo que aprendizaje federado y aprendizaje que preserva la privacidad debe ser y cómo construimos los bloques para que esto pase.\n",
    "\n",
    "- [Mirar los tutoriales de PySyft](https://github.com/OpenMined/PySyft/tree/master/examples/tutorials)\n",
    "\n",
    "### ¡Únete a nuestro Slack!\n",
    "\n",
    "La mejor manera de mantenerte actualizado con los últimos avances es ¡unirte a la comunidad!\n",
    "\n",
    "- [Unirse a slack.openmined.org](http://slack.openmined.org)\n",
    "\n",
    "### ¡Únete a un proyecto de código!\n",
    "\n",
    "La mejor manera de contribuir a nuestra comunidad es convertirte en un ¡contribuidor de código! Si quieres empezar un mini proyecto, puedes ir a la página  _PySyft GitHub Issues_ y buscar por _issues_ marcados como `Good First Issue`.\n",
    "\n",
    "- [Good First Issue Tickets](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
    "\n",
    "### Donar\n",
    "\n",
    "Si no tienes tiempo para contribuir a nuestra base de código, pero quieres ofrecer tu ayuda, también puedes aportar a nuestro _Open Collective_. Todas las donaciones van a nuestro web hosting y otros gastos de nuestra comunidad como ¡hackathons y meetups!\n",
    "\n",
    "- [Donar a través de la página de OpenMined](https://opencollective.com/openmined)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
